//
//  CS_WIFITransferServices.swift
//  NewSS
//
//  Created by 杨馥瑞 on 2021/9/7.
//

import UIKit

class CS_WIFITransferServices: NSObject, GCDWebServerDelegate {
    
    weak var delegate: CS_WifiTransferServicesDelegate?
    
    private var _sercerURL = ""
    private var _server: GCDWebServer?
    private var _allowedIPs: [String] = [String]()
    
    var isRunning: Bool { _server?.isRunning ?? false }
    
    var displayURL: String {
        let serUrl = _server?.serverURL?.absoluteString ?? ""
        if serUrl.isEmpty { return "" }
        let urlArray = serUrl.components(separatedBy: ":")
        if urlArray.count > 1, urlArray.count < 3 {
            return urlArray[1].replacingOccurrences(of: "/", with: "")
        }
        else {
            // substringToIndex: serUrl.count - 1
            let start = serUrl.startIndex
            let end = serUrl.index(serUrl.startIndex, offsetBy: serUrl.count-1)
            return String(serUrl[start..<end])
        }
    }
    
    override init() {
        super.init()
        _server = GCDWebServer()
        _server?.delegate = self
        
        weak var service = self
        
        let bundlePath = Bundle.main.path(forResource: "WIFITransferWeb", ofType: "bundle") ?? ""
        let siteBundleResourcePath = Bundle(path: bundlePath)?.resourcePath ?? ""
        
        // 静态网页
        _server?.addGETHandler(forBasePath: "/",
                               directoryPath: siteBundleResourcePath,
                               indexFilename: nil,
                               cacheAge: 3600,
                               allowRangeRequests: false
        )
        
        // 指定首页
        _server?.addHandler(forMethod: "GET",
                            path: "/",
                            request: GCDWebServerRequest.self,
                            processBlock: { request in
            return service?._indexPage(for: request)
        })
        
        // ping API for query status，需要配置，不然一直自动断掉链接
        _server?.addHandler(forMethod: "GET",
                            path: "/ping",
                            request: GCDWebServerRequest.self,
                            processBlock: { request in
            return GCDWebServerDataResponse(text: "1")
        })
        
        // upload file with multipart post form
        _server?.addHandler(match: { requestMethod, reuqestURL, requestHeaders, urlPath, urlQuery in
            if urlPath.caseInsensitiveCompare("/upload") != .orderedSame {
                return nil
            }
            CJLog("equestHeaders: \(requestHeaders) urlQuery: \(urlQuery)")
            return GCDWebServerMultiPartFormRequest(method: requestMethod, url: reuqestURL, headers: requestHeaders, path: urlPath, query: urlQuery)
        }, processBlock: { [weak self] request in
            guard let multiRequest = request as? GCDWebServerMultiPartFormRequest,
                  let file = multiRequest.files.first,
                  let self = self
            else { return service?._responseForNotAllowAccess() } // 上传失败
            
            DispatchQueue.main.async {
                let item = CS_WifiTransferFileItem()
                item.fileName = file.fileName
                item.filePath = file.temporaryPath
                item.fileSize = 0 //TODO: 计算文件大小
                self.delegate?.transferServices(self, didRecieveFileSuccess: item)
            }
            // 成功上传
            return GCDWebServerDataResponse(text: "1")
        })
        
        // 监听通知
        NotificationCenter.default.addObserver(
            self,
            selector: #selector(_startRecvFile(_:)),
            name: NSNotification.Name(kNotifyGCDWebServerMultiPartFormRequestStartRecvFile),
            object: nil
        )
    
    }
    
    deinit {
        _server = nil
    }
    
    // MARK: - 外部方法
    
    @discardableResult
    func start() -> Bool {
        guard let server = _server else { return false }
        var ret = true
        let defaultPorts: [UInt] = [80, 88, 8888, 8080]
        for port in defaultPorts {
            ret = server.start(withPort: port, bonjourName: nil)
            if ret {
                return ret
            }
        }
        if !ret {
            ret = server.start(withPort: 0, bonjourName: nil)
            CJAssert(ret, "wifi service start error")
        }
        return ret
    }
    
    func stop() {
        _server?.stop()
    }
    
    func reset() {
        
    }
    
    func allowClientAccess(_ allowIp: String) {
        guard !allowIp.isEmpty else {
            return
        }
        _allowedIPs.append(allowIp)
    }
    
    // MARK: - 代理
    
    func webServerDidStart(_ server: GCDWebServer) {
        DispatchQueue.main.async {
            self.delegate?.transferServicesDidStart(self)
        }
    }
    
    func webServerDidConnect(_ server: GCDWebServer) {
        DispatchQueue.main.async {
            self.delegate?.transferServicesDidReceiveConnect(self)
        }
    }
    
    func webServerDidDisconnect(_ server: GCDWebServer) {
        DispatchQueue.main.async {
            self.delegate?.transferServicesDidDisConnect(self)
        }
    }
    
    func webServerDidStop(_ server: GCDWebServer) {
        
    }
    
    // MARK: - 通知
    
    @objc private func _startRecvFile(_ notification: NSNotification) {
        guard let fileName = notification.userInfo?["fileName"] as? String else {
            return
        }
        DispatchQueue.main.async {
            let item = CS_WifiTransferFileItem()
            item.fileName = fileName
            item.fileSize = 0   //TODO: 计算文件大小
            self.delegate?.transferServices(self, didReceiveSendingFile: item)
        }
    }
    
    // MARK: - 私有方法
    
    /// 静态网页的首页
    private func _indexPage(for request: GCDWebServerRequest) -> GCDWebServerResponse? {
        guard let siteBundlePath = Bundle.main.path(forResource: "WIFITransferWeb", ofType: "bundle"),
              let siteBundle = Bundle(path: siteBundlePath),
              let indexFilePath = siteBundle.path(forResource: "index", ofType: "html")
        else { return nil }
        
        return GCDWebServerFileResponse(file: indexFilePath)
    }
    
    private func _readableIpForConnection(_ connection: GCDWebServerConnection) -> String {
        return connection.remoteAddressString.components(separatedBy: ":").first ?? ""
    }
    
    private func _responseForNotAllowAccess() -> GCDWebServerDataResponse? {
        return GCDWebServerDataResponse(text: "-1")
    }

}

protocol CS_WifiTransferServicesDelegate: NSObjectProtocol {
    /// 开始连接
    func transferServicesDidStart(_ service: CS_WIFITransferServices)
    /// 收到pc连接回调
    func transferServicesDidReceiveConnect(_ service: CS_WIFITransferServices)
    /// 是否同意连接
    func transferServices(_ service: CS_WIFITransferServices, didRequestAcess ipAddress: String)
    /// 开始发送文件
    func transferServices(_ service: CS_WIFITransferServices, didReceiveSendingFile file: CS_WifiTransferFileItem)
    /// 接收文件成功
    func transferServices(_ service: CS_WIFITransferServices, didRecieveFileSuccess file: CS_WifiTransferFileItem)
    /// 接收文件失败
    func transferServices(_ service: CS_WIFITransferServices, didRecieveFileFail file: CS_WifiTransferFileItem)
    /// 失去连接
    func transferServicesDidDisConnect(_ service: CS_WIFITransferServices)
}

extension CS_WifiTransferServicesDelegate {
    func transferServicesDidStart(_ service: CS_WIFITransferServices) {}
    func transferServicesDidReceiveConnect(_ service: CS_WIFITransferServices) {}
    func transferServices(_ service: CS_WIFITransferServices, didRequestAcess ipAddress: String) {}
    func transferServices(_ service: CS_WIFITransferServices, didReceiveSendingFile file: CS_WifiTransferFileItem) {}
    func transferServices(_ service: CS_WIFITransferServices, didRecieveFileSuccess file: CS_WifiTransferFileItem) {}
    func transferServices(_ service: CS_WIFITransferServices, didRecieveFileFail file: CS_WifiTransferFileItem) {}
    func transferServicesDidDisConnect(_ service: CS_WIFITransferServices) {}
}

class CS_WifiTransferFileItem: Equatable {
    var fileName = ""
    var filePath = ""
    var fileSize: UInt = 0
    
    static func == (lhs: CS_WifiTransferFileItem, rhs: CS_WifiTransferFileItem) -> Bool {
        return lhs.fileName == rhs.fileName
    }
}
